在ReactNative开发中,目前为止,活动页面之间的跳转使用Navigator来实现。但是在实际使用中却有着不为人知的秘密……

Navigator allow you to manage the navigation in your app between various “scenes” (another word for screens). They manage a route stack and allow you to pop, push, and replace states. In this way, they are similar to the html5 history API. Navigator re-implements that functionality entirely in JavaScript as a React component. A corollary of this is that Navigator will be compatible with Android and iOS
——Facebook ReactNative Official Introduction

##基本概念

  • navigator : 一个用来管理所有界面对象的栈,人称之 “路由栈”, 学名 “导航”。
  • route : 路由栈里的每一个对象,称之为 “路由”,用来存储每一个页面组件以及一些需要传递给对应界面的props参数。

使用Navigator来导航整个App页面

在Android中,我们都知道管理Activity的Task栈。由此可知,我们需要把Navigator放在一个常驻的界面中。因此我们在这里放在整个ReactNative工程的入口——index.ios.js/index.android.js 中。

为项目添加Navigator控制

  1. 第一步需要做的依旧是引入Navigator组件 (以下React已import导入)
    • 加入全局的名字空间以方便使用 let { Navigator } = React
    • 或者以React.Navigator 的方式直接使用
  2. 使用Navigator组件

    return (
    <Navigator style = {styles.container}
    initialRoute={{
    name: 'HomePage'// 可选
    component: HomePage
    }}
    configureScene={(route) => {
    return Navigator.SceneConfigs.VerticalDownSwipeJump
    }}
    renderScene={(route, navigator) => {
    return <route.component navigator={navigator} {...route} {...route.passProps}/>
    }}/>
    )
    • initialRoute: 初始路由,也就是我们需要在navigator栈底放置的路由,因为此时也是栈顶,因此也就是初始化整个App的首页。
    • configureScene: 设置页面切换动画,具体的值大家可以在node_modules/react-native/Libraries/CustomComponents/Navigator/NavigatorSceneConfigs.js 源库中找到。或者直接在sublime Text 3 中使用命令command+p 命令,然后输入NavigatorSceneConfigs进行文件搜索。笔者看了一下,大概有不到十种动画,这里就不做具体介绍了。
    • renderScene: 渲染当前路由场景,也就是渲染栈顶路由。回调方法里一个参数是当前路由route,另一个是navigator 路由栈。这里需要细讲一下:
      • route: 路由里包含一个必要的component变量和一些可选的参数,而component则就是当前需要渲染的组件。其他的一些可选的参数也是以键值对的方式保存在route对象中,并在这里以属性的方式传递给对应的component组件中。
      • navigator: 这是Navigator组件在本回调方法中的参数,也就是我们在前边提到的路由栈。会在每次渲染新route的时候以属性的形式传递给route中component的对象。它可以在对应的场景中做一些操作,这里我们给出官方的部分文档:
        • getCurrentRoutes() - 获取当前栈里的路由,也就是push进来,没有pop掉的那些。
        • jumpBack() - 跳回之前的路由,当然前提是保留现在的,还可以再跳回来,会给你保留原样。
        • jumpForward() - 上一个方法不是调到之前的路由了么,用这个跳回来就好了。
        • jumpTo(route) - 跳转到已有的场景并且不卸载。
        • push(route) - 跳转到新的场景,并且将场景入栈,你可以稍后跳转过去
        • pop() - 跳转回去并且卸载掉当前场景
        • replace(route) - 用一个新的路由替换掉当前场景
        • replaceAtIndex(route, index) - 替换掉指定序列的路由场景
        • replacePrevious(route) - 替换掉之前的场景
        • immediatelyResetRouteStack(routeStack) - 用新的路由数组来重置路由栈
        • popToRoute(route) - pop到路由指定的场景,其他的场景将会卸载。
        • popToTop() - pop到栈中的第一个场景,卸载掉所有的其他场景。
      • {...route} 这是一句 es6 语法,表示将route中所有的键值对以属性赋值的方式展开,也就是{name: 'pober', gender: 'man'}name = 'pober' gender = 'man'之间的转换。这样就把route对象中所有的键值对就很容易地放到route.component组件的props属性中去啦~因此,这个语法在自定义控件的时候也经常用到,主要用来兼容组件中其他所有的属性,如自定义ListView兼容官方ListView的所有属性。
      • passProps 这是一个我们自己定义的key,后边会提到。同样是可选的
  3. 在对应页面中使用navigator路由栈进行基本的操作
    在上边也提到了navigator的一些列方法。这里我们核心介绍一下push和pop的操作。

    • push(route): 跳转到下一个场景同时将它入栈。我们看一下以下代码

      this.props.navigator.push({
      component: NextPage,
      passProps: {name: 'pober'} // 传递的参数(可选),{}里都是键值对 ps: test是关键字
      })

以上这段代码可以放在任何你需要监听跳转的地方,同样也可以传递任何你想要的参数。

* 这里括号里的部分就是一个对象。我们也可以把它单独拿出来赋给route变量 (如果不能理解的话)
* `component`:即就是我们需要呈现的组件 
* `passProps` 这是[NavigatorIOS](http://facebook.github.io/react-native/docs/navigatorios.html#content) 中常用的一个属性,这里我们加上是为了让它们看起来更加统一一些。当然啦,既然是手动加的,那命名当然是随意的了,只要和Navigator组件里声明的一样即可。  

注意,test应该是React中的某个关键字,如果在passProps里声明的话,在下一个界面里是拿不到的。 当然,有了前边{...route}我们显然是没必要再去包裹一层参数,当然如果不是为了语义上的准确

  • pop() 顾名思义就是一个对navigator栈弹栈的过程,这经常发生在NavigationBar中的Back事件中。

项目实战

这里我们只进行几个必要的操作

  1. 将上次的History页面抽取出一个单独的js文件,我们在这里叫做History.js ,放在了js.core 文件夹下,并在index.ios.js中引入之。

  2. 然后在index.ios.js中按照以上步骤加入Navigator组建的使用,设置初始路由为History页面,如果此时运行的效果和之前一样的话,就算是OK啦…

  3. 接着我们开始利用Navigator进行页面跳转的实践吧~
    创建一个新的页面,我们叫HelloWorld.js吧,然后在History页面导入之,然后进行路由跳转即可。
    History 更改如下代码:

      _renderItem (contentData, sectionID, highlightRow) {
    return (
    <TouchableHighlight
    onPress = {() => this.props.navigator.push({
    component: HelloWorld,
    passProps: {geeker: 'pober'}
    })}>
    <View style={styles.itemContainer}>
    <Text style={[styles.title]}>{contentData.title}</Text>
    <Image source={{uri: contentData.uri}}
    style={styles.thumbnail}/>
    </View>
    </TouchableHighlight>
    )
    }
    ```
    其实也就是给外层的`TouchableHighlight`添加一个点击事件,然后添加的代码和上个模块的`push`操作一样。我们还加入了一个key为geeker的键值对,值是我的名字`pober`。

    4. 此时,做完以上三点,已经能够从History页面跳转到HelloWorld页面了。接下来我们再做一个navigator栈的操作——`pop`
    很简单,这里我们直接在HelloWorld页面手动执行这个操作就可以了。其实,自带的右滑返回也是这个操作...

    render () {
    return (

    <TouchableOpacity onPress = {() => this.props.navigator.pop()}>
      <Text>{this.props.geeker}</Text>
    </TouchableOpacity>
    


    )
    }
    `
    这里是HelloWorld的核心代码,我们使用了一个按钮,然后上边显示了我们在上一个界面中传入的geeker变量,值当然就是伦家的名字pober啦…点击之后,我们很简单地调用了navigator的pop()方法。

HelloWorld页面截图:

结语

路漫漫其修远兮,吾将上下而求索

未来的路还很长,每个人都在努力的追逐时代的步伐,科技的脚步。现在ReactNative已经更新到 0.20.0了,相信在未来的不久,这位酷似大卫的神级偶像 扎克伯格 将会带领我们走向全新的潮流。

项目源码

以上部分代码已经放在 我的Github上,欢迎来访查看。

作者:poberWong
发布时间:2016-02-21 19:30
更新时间:2016-02-28 16:07
版权声明:自由转载 - 不可商用 - 不可衍生 - 保持署名 (请遵守:CreativeCommons 3.0协议)

donation